from petiteappli.xenocide.world import World

#import petiteappli.xenocide.util as util
import math

import os
import logging


import ogre.renderer.OGRE as ogre
import ogre.io.OIS as OIS
import ogre.gui.CEGUI as CEGUI





class EventListener(ogre.FrameListener, ogre.WindowEventListener, OIS.MouseListener, OIS.KeyListener, OIS.JoyStickListener):
    """
    This class handles all our ogre and OIS events, mouse/keyboard/joystick
    depending on how you initialize this class. All events are handled
    using callbacks (buffered).
    """
 
    mouse = None
    keyboard = None
    joy = None
 
    def __init__(self, renderWindow, bufferedMouse, bufferedKeys, bufferedJoy,callback,iParent):
 
        # Initialize the various listener classes we are a subclass from
        ogre.FrameListener.__init__(self)
        ogre.WindowEventListener.__init__(self)
        OIS.MouseListener.__init__(self)
        OIS.KeyListener.__init__(self)
        OIS.JoyStickListener.__init__(self)
    
        self.parent=iParent
        
        self.renderWindow = renderWindow
        
        self.parentCallback = callback
        
        # Create the inputManager using the supplied renderWindow
        windowHnd = self.renderWindow.getCustomAttributeInt("WINDOW")
        self.inputManager = OIS.createPythonInputSystem([("WINDOW",str(windowHnd))])
 
        # Attempt to get the mouse/keyboard input objects,
        # and use this same class for handling the callback functions.
        # These functions are defined later on.
 
        try:
            if bufferedMouse:
                self.mouse = self.inputManager.createInputObjectMouse(OIS.OISMouse, bufferedMouse)
                self.mouse.setEventCallback(self)
 
            if bufferedKeys:
                self.keyboard = self.inputManager.createInputObjectKeyboard(OIS.OISKeyboard, bufferedKeys)
                self.keyboard.setEventCallback(self)
 
            if bufferedJoy:
                self.joy = self.inputManager.createInputObjectJoyStick(OIS.OISJoyStick, bufferedJoy)
                self.joy.setEventCallback(self)
 
        except Exception, e: # Unable to obtain mouse/keyboard/joy input
            raise e
 
        # Set this to True when we get an event to exit the application
        self.quitApplication = False
 
        # Listen for any events directed to the window manager's close button
        ogre.WindowEventUtilities.addWindowEventListener(self.renderWindow, self)
        self.windowResized(self.renderWindow)
        
    def __del__ (self ):
        # Clean up OIS 
        print "QUITING"
        self.delInputObjects()
 
        OIS.InputManager.destroyInputSystem(self.inputManager)
        self.inputManager = None
 
        ogre.WindowEventUtilities.removeWindowEventListener(self.renderWindow, self)
        self.windowClosed(self.renderWindow)
 
    def delInputObjects(self):
        # Clean up the initialized input objects
        if self.keyboard:
            self.inputManager.destroyInputObjectKeyboard(self.keyboard)
        if self.mouse:
            self.inputManager.destroyInputObjectMouse(self.mouse)
        if self.joy:
            self.inputManager.destroyInputObjectJoy(self.mouse)
 
    def frameStarted(self, evt):
        """ 
        Called before a frame is displayed, handles events
        (also those via callback functions, as you need to call capture()
        on the input objects)
 
        Returning False here exits the application (render loop stops)
        """
 
        # Capture any buffered events and call any required callback functions
        if self.keyboard:
            self.keyboard.capture()
        if self.mouse:
            self.mouse.capture()
        if self.joy:
            self.joy.capture()
 
        self.parentCallback(evt)
        # Neatly close our FrameListener if our renderWindow has been shut down
        if(self.renderWindow.isClosed()):
            return False
        
        return not self.quitApplication
 
### Window Event Listener callbacks ###
 
    def windowResized(self, renderWindow):
        mouseState = self.mouse.getMouseState()
        mouseState.width = renderWindow.getViewport(0).getActualWidth()
        mouseState.height = renderWindow.getViewport(0).getActualHeight()

 
    def windowClosed(self, renderWindow):
        # Only close for window that created OIS
        if(renderWindow == self.renderWindow):
            del self
 
### Mouse Listener callbacks ###
 
    def mouseMoved(self, evt):
        # Pass the location of the mouse pointer over to CEGUI
        CEGUI.System.getSingleton().injectMouseMove(evt.get_state().X.rel, evt.get_state().Y.rel)
        
        return True
 
    def mousePressed(self, evt, id):
        # Handle any CEGUI mouseButton events
        
        CEGUI.System.getSingleton().injectMouseButtonDown(self.convertButton(id))
        return self.parent.doMouseDown(evt,id,self.keyboard.isModifierDown(OIS.Keyboard.Modifier.Shift),\
                                        self.keyboard.isModifierDown(OIS.Keyboard.Modifier.Ctrl),\
                                        self.keyboard.isModifierDown(OIS.Keyboard.Modifier.Alt))
        
        
    def mouseReleased(self, evt, id):
        # Handle any CEGUI mouseButton events
        CEGUI.System.getSingleton().injectMouseButtonUp(self.convertButton(id))
        return self.parent.doMouseUp(evt,id,self.keyboard.isModifierDown(OIS.Keyboard.Modifier.Shift),\
                                        self.keyboard.isModifierDown(OIS.Keyboard.Modifier.Ctrl),\
                                        self.keyboard.isModifierDown(OIS.Keyboard.Modifier.Alt))
        
 
 
    def convertButton(self,oisID):
        if oisID == OIS.MB_Left:
            return CEGUI.LeftButton
        elif oisID == OIS.MB_Right:
            return CEGUI.RightButton
        elif oisID == OIS.MB_Middle:
            return CEGUI.MiddleButton
        else:
            return CEGUI.LeftButton     
 
### Key Listener callbacks ###
 
    def keyPressed(self, evt):
        # Quit the application if we hit the escape button
        if evt.key == OIS.KC_ESCAPE:
            self.quitApplication = True
 
        if evt.key == OIS.KC_1:
            print "hello"
            return True
        
        if evt.key == OIS.KC_2:
            self.parent.test()
            return True
        if evt.key == OIS.KC_3:
            self.parent.test2()
            return True
  
    def keyReleased(self, evt):
        return True

### Joystick Listener callbacks ###
 
    def buttonPressed(self, evt, id):
        return True
 
    def buttonReleased(self, evt, id):
        return True
 
    def axisMoved(self, evt, id):
        return True
 

class MainWindow(ogre.RaySceneQueryListener):

    
    
    app_title="Xenocide alpha"
    def __init__(self):
        self.raySceneQuery = None
        super ( MainWindow, self ).__init__() 
    
    def go(self):
        
        self.perspective=True
        
        self.createRoot()
        self.defineResources()
        self.setupRenderSystem()
        self.createRenderWindow()
        self.initializeResourceGroups()
        self.createSceneManager()
        self.createCamera()
        self.setupScene()
        self.createFrameListener()
        self.setupCEGUI()
        self.startRenderLoop()
    
    def createRoot(self):
        self.root = ogre.Root()
 
    def defineResources(self):
        # Read the resources.cfg file and add all resource locations in it
        cf = ogre.ConfigFile()
        cf.load("resources.cfg")
        seci = cf.getSectionIterator()
        while seci.hasMoreElements():
            secName = seci.peekNextKey()
            settings = seci.getNext()
 
            for item in settings:
                typeName = item.key
                archName = item.value
                ogre.ResourceGroupManager.getSingleton().addResourceLocation(archName, typeName, secName)
        
    def createRenderWindow(self):
        self.root.initialise(True, self.app_title)
 
    def initializeResourceGroups(self):
        ogre.TextureManager.getSingleton().setDefaultNumMipmaps(5)
        ogre.ResourceGroupManager.getSingleton().initialiseAllResourceGroups()
 
    
    def createSceneManager(self): 
        """
            /// Creates the scene manager which will be used.
            /// If you override this function, you must set the SceneManager property of this
            /// class to be the result.  Example:
            ///   this.SceneManager = this.Root.CreateSceneManager(...);
        """   
        self.stop = True
        self.SceneMgr = self.root.createSceneManager(ogre.SceneType.ST_GENERIC, "Default SceneManager")
        self.SceneMgr.ShadowTechnique = ogre.ShadowTechnique.SHADOWTYPE_STENCIL_ADDITIVE
        self.SceneMgr.ShadowFarDistance = 15000.0
        
        if False:
                # Allow self shadowing (note: this only works in conjunction with the shaders defined above)
                self.SceneMgr.setShadowTextureSelfShadow(True)
                # Set the caster material which uses the shaders defined above
                self.SceneMgr.setShadowTextureCasterMaterial("Ogre/DepthShadowmap/Caster/Float")
                # Set the pixel format to floating point
                self.SceneMgr.setShadowTexturePixelFormat(ogre.PF_FLOAT32_R)
                # You can switch this on or off, I suggest you try both and see which works best for you
                self.SceneMgr.setShadowCasterRenderBackFaces(False);
                # Finally enable the shadows using texture additive integrated
                self.SceneMgr.setShadowTechnique(ogre.ShadowTechnique.SHADOWTYPE_TEXTURE_ADDITIVE_INTEGRATED)

    def createCamera(self):
        """Creates the camera for this class.
        #/ If you override this function, you must set the Camera property of this class
        #/ to be the result.  Example:
        #/   this.Camera = this.SceneManager.CreateCamera(...);
        """
        self.camera = self.SceneMgr.createCamera("Camera")
        
        self.cameraNode=self.SceneMgr.getRootSceneNode().createChildSceneNode()
        self.cameraNode.attachObject(self.camera)
        if self.perspective:
            
            self.camera.NearClipDistance =10

            self.cameraNode.setPosition(ogre.Vector3(0, 6000, 0))
            self.camera.pitch(ogre.Degree(-90))
            self.camera.autoAspectRatio = True
            self.camera.FOVy = ogre.Radian(math.pi / 10)
            self.camera.setFarClipDistance(20000.)
            
        else :
                halfWidth,halfHeight=800.,400.
                self.camera.setNearClipDistance(10.)
                
                self.cameraNode.setPosition(ogre.Vector3(0, 500., 0))
                self.camera.pitch(ogre.Degree(-90))
            
                self.camera.setProjectionType(ogre.PT_ORTHOGRAPHIC)
                self.camera.setOrthoWindow(1600.,1200.)
                self.camera.setFarClipDistance(2000.)
                #self.camera.autoAspectRatio = True
                #self.camera.FOVy = ogre.Radian(math.pi / 4)
                
                
       
        viewPort = self.root.getAutoCreatedWindow().addViewport(self.camera)
        

        
    
    def doFrameStarted(self,evt):
        
        """
        self.camera.Position = self.camera.Position \
            + self.camera.Orientation * self.translation * 3.0 \
            * evt.timeSinceLastFrame"""
        self.world.doFrameStarted(evt)    
        return self.stop

    def test(self):
        self.world.test()
        
    def setupRenderSystem(self):
        # Show the config dialog if we don't yet have an ogre.cfg file
        if not self.root.restoreConfig() and not self.root.showConfigDialog():
            raise Exception("User canceled config dialog! (setupRenderSystem)")
    
    
    def setupScene(self):
        
    
        self.renderWindow = self.root.getAutoCreatedWindow()
        
        
        
        
        self.mapDim= (1600,1200)
        

        
        self.SceneMgr.AmbientLight = ogre.ColourValue(0.5, 0.5, 0.5)
        
        floorPlane = ogre.Plane(ogre.Vector3.UNIT_Y, -10)
        ogre.MeshManager.getSingleton().createPlane("ground",\
                    ogre.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,\
                    floorPlane,\
                    self.mapDim[0], self.mapDim[1], 255, 255, \
                    True, 1, 1, 1, ogre.Vector3.UNIT_Z)

        ent = self.SceneMgr.createEntity("GroundEntity", "ground")
        ent.setQueryFlags(World.TERRAIN_MASK)
        
        sn=self.SceneMgr.getRootSceneNode().createChildSceneNode()
        sn.attachObject(ent)
        sn.translate(0.5*self.mapDim[0],0.0,0.5*self.mapDim[1])
        
        self.cameraNode.translate(0.5*self.mapDim[0],0.0,0.5*self.mapDim[1])
            
        # Make mesh for barrier links
        ogre.MeshManager.getSingleton().createPlane("barrierlink",\
                      ogre.ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME, floorPlane,\
                    32.0, 32.0, 1, 1,True,1,1,1,ogre.Vector3.UNIT_Z)


        
        ent.setMaterialName("Alpha/Ground")
        ent.setCastShadows (False)
        
        
        
##        for i in range(len(svg.getPaths())):
##            mo=svg.makeMesh(i,100.,"Bob"+str(i))
##            ent = self.SceneMgr.createEntity("test"+str(i),"Bob"+str(i)+"Mesh")
##            ent.setCastShadows (True)
##        
##            sn=self.SceneMgr.getRootSceneNode().createChildSceneNode()
##            sn.translate(-500.,-10.,-500.0)
##        
##            sn.attachObject(ent)
##        
##            ent.setQueryFlags(World.TERRAIN_MASK)
        
            
        self.world=World(self,self.mapDim)

        
        self.selectionMarker=self.world.BBS
        
            
        mE=self.world.spawnMobileActor("Radar1",ogre.Vector3(-20,0,5),\
                                ogre.Quaternion(ogre.Vector3.UNIT_X,\
                                ogre.Vector3.UNIT_Y,ogre.Vector3.UNIT_Z),\
                                "Radar_Vehicule.mesh",None)

        self.world.spawnMobileActor("Radar2", ogre.Vector3(-50, 0, 205),\
                                ogre.Quaternion(ogre.Vector3.UNIT_X,\
                                ogre.Vector3.UNIT_Y,ogre.Vector3.UNIT_Z),\
                                "Radar_Vehicule.mesh",None)
                                
        
        bp1=self.world.spawnBarrierPole(ogre.Vector3(30.0, 30.0, 30.0))
        bp2=self.world.spawnBarrierPole(ogre.Vector3(250.0, 30.0, -30.0))
        bp3=self.world.spawnBarrierPole(ogre.Vector3(100, 30.0, -280))
        
        self.world.createBarrierLink(bp2,bp1)
        self.world.createBarrierLink(bp2, bp3)

        self.world.SelectedObject = mE

            
    def createFrameListener(self):
        self.eventListener = EventListener(self.renderWindow, True, True, False,self.doFrameStarted,self)
        self.root.addFrameListener(self.eventListener)
 
    def setupCEGUI(self):
        sceneManager = self.SceneMgr
 
        # CEGUI
        # Another fix for CEGUI to ensure we get a working parser..
        if os.name == 'nt':
            CEGUI.System.setDefaultXMLParserName("ExpatParser")
        else:
            CEGUI.System.setDefaultXMLParserName("TinyXMLParser")

        self.renderer = CEGUI.OgreCEGUIRenderer(self.renderWindow, ogre.RENDER_QUEUE_OVERLAY, False, 3000, sceneManager)
        self.system = CEGUI.System(self.renderer)
 
        CEGUI.SchemeManager.getSingleton().loadScheme("TaharezLookSkin.scheme")
        self.system.setDefaultMouseCursor("TaharezLook", "MouseArrow")
        self.system.setDefaultFont("BlueHighway-12")
 
        CEGUI.MouseCursor.getSingleton().show()

        # Uncomment the following to read in a CEGUI sheet (from CELayoutEditor)
        # 
        self.mainSheet = CEGUI.WindowManager.getSingleton().loadWindowLayout("xenocide.layout")
        self.system.setGUISheet(self.mainSheet)
        
 
    def startRenderLoop(self):
        
        self.root.startRendering()
 
    def cleanUp(self):
        # Clean up CEGUI
        print "CLEANING"
        #del self.renderer
        del self.system
 
        # Clean up Ogre
        #del self.exitListener
        del self.root
 
    def doQuery(self,evt,mask):
        # Setup the ray scene query, use CEGUI's mouse position
        mousePos = CEGUI.MouseCursor.getSingleton().getPosition()
        self.mouseRay = self.camera.getCameraToViewportRay(mousePos.d_x / float(evt.get_state().width),
                                                      mousePos.d_y / float(evt.get_state().height))
        
        
        print str((mousePos.d_x,mousePos.d_y))
        print (mousePos.d_x / float(evt.get_state().width),
                                                      mousePos.d_y / float(evt.get_state().height))
        raySceneQuery = self.SceneMgr.createRayQuery(self.mouseRay)
        # Execute query
        raySceneQuery.setSortByDistance(True)
        raySceneQuery.setQueryMask ( mask )
            
        raySceneQuery.execute(raySceneQuery)
        result=raySceneQuery.getLastResults()
        
        if len(result)>0:
            #result.reverse()
            for item in result:
                if item.movable :
                    print "MovableObject: " + str(item.movable.getName())
                    
                    if (mask & World.SELECTABLE_MASK):
                        tmp= self.world.getSelectableByName(item.movable.getName())
            
                        if tmp is not None:

                            if tmp is self.world.currentSelection:
                                print "QUERY_CURRENT_ACTOR"
                                return tuple([self.world.QUERY_CURRENT_ACTOR,ogre.Vector3.ZERO,tmp])
                            elif tmp.getSelected is not None:
                                print "QUERY_OTHER_OBJECT"
                                return tuple([self.world.QUERY_OTHER_OBJECT,ogre.Vector3.ZERO,tmp])
                    if mask & World.TERRAIN_MASK :
                        if (item.movable.getName()=="GroundEntity") :
                    
                            floorPlane = ogre.Plane(ogre.Vector3.UNIT_Y, 0)
                            p = self.mouseRay.intersects(floorPlane)
                            if (p.first) :
                            
                                position = self.mouseRay.getPoint(p.second)
                                print "QUERY_GROUND at %s"%(str(position))
                                return tuple([World.QUERY_GROUND,position,None])
                            
                    
                        
        return None    
        
        
    def doMouseUp(self,evt,id,isShift,isCtrl,isAlt):
        
        q=None
        if id==OIS.MB_Right :
            q= self.doQuery(evt,World.TERRAIN_MASK)
        if id==OIS.MB_Left :
            q= self.doQuery(evt,self.world.SELECTABLE_MASK)
        
        if q:
            return self.world.doMouseUp(q[1],id,isShift,isCtrl,isAlt,q[0],q[2])
        return True
    
    def doMouseDown(self,evt,id,isShift,isCtrl,isAlt):
        
        return True
    
    def test2(self):
        x=ogre.Vector3(1.,0.,2.).normalisedCopy()
        y=ogre.Vector3(0.,1.,0.)
        z=x.crossProduct(y*-1)
        
        print ("base :"+str(x)+" "+str(y)+" "+str(z))
        
        q=ogre.Quaternion(x,y,z)

        print ("result : %s %s %s"%(str(q.xAxis()),str(q.yAxis()),str(q.zAxis())))
        
        
        
    
if __name__ == '__main__':
    
    

    try:
        ta = MainWindow()
        ta.go()
        #ta.test2()
    except ogre.OgreException, e:
        print e
            
            
                
